import {
    mxClient,
    mxUtils,
    mxEvent,
    mxGraph,
    mxMarker,
    mxEditor,
    mxOutline,
    mxGraphModel,
    mxConstants,
    mxCodec,
    mxPerimeter,
    mxGraphHandler,
    mxEdgeHandler,
    mxEdgeStyle,
    mxToolbar,
    mxCell,
    mxGeometry,
    mxUndoManager,
    mxPolyline,
    mxCellState,
    mxConnectionConstraint,
    mxShape,
    mxPoint,
    mxConstraintHandler,
    mxEllipse,
    mxClipboard,
    mxKeyHandler,
    mxRubberband,
    mxCylinder,
    mxCellRenderer,
    mxDragSource,
} from '../assets/mxgraph/4.0.0/mxgraph'

import './Shapes'

import rectangleImg from '../assets/mxgraph/4.0.0/images/rectangle.png'
import readAndWriteImg from '../assets/mxgraph/4.0.0/images/edge1.png'
import onlyReadImg from '../assets/mxgraph/4.0.0/images/edge2.png'
import writeImg from '../assets/mxgraph/4.0.0/images/edge3.png'
import deleteImg from '../assets/mxgraph/4.0.0/images/delete.png'
import editImg from '../assets/mxgraph/4.0.0/images/edit.png'
import ellipseImg from '../assets/mxgraph/4.0.0/images/ellipse.png'
import swimlaneImg from '../assets/mxgraph/4.0.0/images/swimlane.gif'
import rhombusImg from '../assets/mxgraph/4.0.0/images/rhombus.png'
import triangleImg from '../assets/mxgraph/4.0.0/images/triangle.gif'
import cylinderImg from '../assets/mxgraph/4.0.0/images/arcedge.png'
import actorImg from '../assets/mxgraph/4.0.0/images/actor.gif'

class Graph {
    constructor(vm, containerEl, toolbarContainerEl,outlineEl) {
        // graph 画板
        this.container = containerEl;
        // 拖拽条，拖拽条也可以用
        this.toolbarContainer = toolbarContainerEl;
        //editor
        this.editor = new mxEditor();
        // mxGraph
        this.mxGraph = this.editor.graph;
        this.editor.setGraphContainer(this.container);
        //outline
        this.outlineContainer = outlineEl;
        // vm 实例
        this.vm = vm;
        this.undoManager = null;
        // 默认 vertex 样式
        this.defaultStyle = {
            width: 120,
            height: 60
        }
    }
    // read(txt) {
    //     this.mxGraph.getModel().beginUpdate();
    //     try {
    //         const doc = mxUtils.parseXml(txt);
    //         const dec = new mxCodec(doc);
    //         var node = doc.documentElement;
    //         dec.decode(node, this.mxGraph.getModel());
    //     } finally {
    //         this.mxGraph.getModel().endUpdate();
    //
    //     }
    // }
    // out(){
    //     var graph = this.mxGraph;
    //     var encoder = new mxCodec();
    //     var result = encoder.encode(graph.getModel());
    //     var xml = mxUtils.getXml(result);
    //     const blob = new Blob([xml], { type: 'text/plain;charset=utf-8' })
    //     FileSaver.saveAs(blob, 'fileio.xml')
    //     // console.log(xml);
    // }
    /* private*/ enableGuides() {
        // Enables guides
        mxGraphHandler.prototype.guidesEnabled = true

        // Alt disables guides
        mxGraphHandler.prototype.useGuidesForEvent = function(me) {
            return !mxEvent.isAltDown(me.getEvent())
        }

        // Defines the guides to be red (default)
        mxConstants.GUIDE_COLOR = '#FF0000'

        // Defines the guides to be 1 pixel (default)
        mxConstants.GUIDE_STROKEWIDTH = 1

        // Enables snapping waypoints to terminals
        mxEdgeHandler.prototype.snapToTerminals = true
    }
    /* private */ setKeyHandler() {
        const graph = this.mxGraph
        const vm = this.vm
        const undoManager = new mxUndoManager()
        const listener = function(sender, evt) {
            undoManager.undoableEditHappened(evt.getProperty('edit'))
        }
        const keyHandler = new mxKeyHandler(graph)

        // 绑定删除键
        keyHandler.bindKey(46, function(evt) {
            if (graph.isEnabled()) {
                vm.$confirm('确定删除吗')
                    .then(res => {
                        graph.removeCells()
                    })
                    .catch(cancel => console.log(cancel))
            }
        })
        // 绑定Ctrl+A全选
        keyHandler.bindControlKey(65, function(evt) {
            if (graph.isEnabled()) {
                graph.selectAll()
            }
        })
        // 绑定Ctrl+C复制节点
        keyHandler.bindControlKey(67, function(evt) {
            if (graph.isEnabled()) {
                var cells = graph.getSelectionCells()
                if (cells.length > 0) {
                    cells = graph.cloneCells(cells)
                    var newCells = []
                    // 修改 cells 中的元素属性
                    cells.forEach(function(cell, i) {
                        cell.id = ''
                        cell.value = (cell.value || '') + '_1'
                        newCells.push(cell)
                    })
                    mxClipboard.setCells(newCells)
                    mxClipboard.paste(graph)
                }
            }
        })
        // 绑定Ctrl+S保存
        keyHandler.bindControlKey(83, function(evt) {
            if (graph.isEnabled()) {
                // saveXml(graph)
            }
        });
        // 绑定Ctrl+I新增
        // keyHandler.bindControlKey(73, function(evt) {
        //   if (graph.isEnabled()) {
        //     graph.insertVertex(
        //       graphParent,
        //       null,
        //       '请输入文本',
        //       10,
        //       10,
        //       100,
        //       40,
        //       mxStyleList.rectangle
        //     )
        //   }
        // })
        // 绑定Ctrl+Z撤销
        keyHandler.bindControlKey(90, function(evt) {
            if (graph.isEnabled()) {
                undoManager.undo()
            }
        })
        // 绑定Ctrl+Y重做
        keyHandler.bindControlKey(89, function(evt) {
            if (graph.isEnabled()) {
                undoManager.redo()
            }
        })

        graph.isCellDeletable = function(cell) {
            return true
        }
    }
    createMyArrow(widthFactor)
    {
        widthFactor = (widthFactor != null) ? widthFactor : 2;

        return function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
        {
            var endOffsetX = unitX * sw * 1.118;
            var endOffsetY = unitY * sw * 1.118;

            unitX = unitX * (size + sw);
            unitY = unitY * (size + sw);

            var pt = pe.clone();
            pt.x -= endOffsetX;
            pt.y -= endOffsetY;

            var f = (type !== mxConstants.ARROW_CLASSIC && type !== mxConstants.ARROW_CLASSIC_THIN) ? 1 : 3 / 4;
            pe.x += -unitX * f - endOffsetX;
            pe.y += -unitY * f - endOffsetY;
            // 线条尾巴位置
            pe.x = 0.5*((pt.x - 1.8*unitX - unitY / widthFactor)+(pt.x + unitY / widthFactor - 1.8*unitX));
            pe.y = 0.5*((pt.y - 1.8*unitY + unitX / widthFactor)+(pt.y - 1.8*unitY - unitX / widthFactor));
            return function()
            {
                canvas.begin();
                canvas.moveTo(pt.x, pt.y);//箭头最右侧
                //箭头屁股下方
                canvas.lineTo(pt.x - unitX - unitY / widthFactor, pt.y - unitY + unitX / widthFactor);
                canvas.lineTo(pt.x + unitY / widthFactor - unitX, pt.y - unitY - unitX / widthFactor);
                canvas.lineTo(pt.x, pt.y);

                canvas.moveTo(pt.x + unitY / widthFactor - 1.3*unitX, pt.y - 1.3*unitY - unitX / widthFactor);
                canvas.lineTo(pt.x - 1.3*unitX - unitY / widthFactor, pt.y - 1.3*unitY + unitX / widthFactor);
                canvas.lineTo(pt.x - 1.8*unitX - unitY / widthFactor, pt.y - 1.8*unitY + unitX / widthFactor);
                canvas.lineTo(pt.x + unitY / widthFactor - 1.8*unitX, pt.y - 1.8*unitY - unitX / widthFactor);


                canvas.close();


                if (filled)
                {
                    canvas.fillAndStroke();
                }
                else
                {
                    canvas.stroke();
                }
                canvas.stroke();
            };
        }
    };

    //重写图的获取约束点函数&&定义每个形状的约束点&&指定折线没有约束点
    setConnectionConstraint()
    {
        // 重写图的获取约束点函数
        mxGraph.prototype.getAllConnectionConstraints = function(terminal, source)
        {
            if (terminal != null && terminal.shape != null)
            {
                if (terminal.shape.stencil != null)
                {
                    if (terminal.shape.stencil.constraints != null)
                    {
                        return terminal.shape.stencil.constraints;
                    }
                }
                else if (terminal.shape.constraints != null)
                {
                    return terminal.shape.constraints;
                }
            }
            return null;
        };

        // 定义每个形状的约束点
        mxShape.prototype.constraints = [new mxConnectionConstraint(new mxPoint(0.25, 0), true),
            new mxConnectionConstraint(new mxPoint(0.5, 0), true),
            new mxConnectionConstraint(new mxPoint(0.75, 0), true),
            new mxConnectionConstraint(new mxPoint(0, 0.25), true),
            new mxConnectionConstraint(new mxPoint(0, 0.5), true),
            new mxConnectionConstraint(new mxPoint(0, 0.75), true),
            new mxConnectionConstraint(new mxPoint(1, 0.25), true),
            new mxConnectionConstraint(new mxPoint(1, 0.5), true),
            new mxConnectionConstraint(new mxPoint(1, 0.75), true),
            new mxConnectionConstraint(new mxPoint(0.25, 1), true),
            new mxConnectionConstraint(new mxPoint(0.5, 1), true),
            new mxConnectionConstraint(new mxPoint(0.75, 1), true)];

        // 指定折线没有约束点
        mxPolyline.prototype.constraints = null;
    }
    //自定义服务元素（矩形）
    createRect()
    {
        var CustomShape = function(){
            mxShape.call(this);
        };
        mxUtils.extend(CustomShape, mxShape);

        CustomShape.prototype.isRoundable = function (c, x, y, w, h) {
            return true;
        };
        CustomShape.prototype.paintBackground = function (c, x, y, w, h) {
            var events = true;
            if (this.style != null) {
                events = mxUtils.getValue(this.style, mxConstants.STYLE_POINTER_EVENTS, '1') === '1';
            }
            if (events || (this.fill != null && this.fill !== mxConstants.NONE) ||
                (this.stroke != null && this.stroke !== mxConstants.NONE)) {
                if (!events && (this.fill == null || this.fill === mxConstants.NONE)) {
                    c.pointerEvents = false;
                }
                var r = 0;
                if (mxUtils.getValue(this.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) === '1') {
                    r = Math.min(w / 2, Math.min(h / 2, mxUtils.getValue(this.style,
                        mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2));
                }
                else {
                    var f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE,
                        mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;
                    r = Math.min(w * f, h * f);
                }
                //此方法调用 mxSvgCanvas2D.js
                c.roundrect(x, y, w, h, r, r);
                c.fillAndStroke();
                c.begin();
                c.moveTo(x,y+1/5*h);
                c.lineTo(x+w,y+1/5*h);
                c.moveTo(x,y+4/5*h);
                c.lineTo(x+w,y+4/5*h);
                c.stroke();
            }
        };
        mxCellRenderer.registerShape('myshape', CustomShape);
    }

    createMessage(){
       var MessageShape = function () {
           mxCylinder.call(this);
       }
        mxUtils.extend(MessageShape, mxCylinder);
        MessageShape.prototype.redrawPath = function (path, x, y, w, h, isForeground) {
            if (isForeground) {
                // path.moveTo(0, 0);
                // path.lineTo(w / 2, h / 2);
                // path.lineTo(w, 0);
            }
            else {
                path.moveTo(0, 0);
                path.lineTo(w-1/4*w, 0);
                path.lineTo(w, 1/3*h);
                path.lineTo(w, h);
                path.lineTo(0, h);
                path.close();
            }
        };

        // Registers the message shape
        mxCellRenderer.registerShape('message', MessageShape);
    }

    init() {
        this.setConnectionConstraint();
        // Checks if the browser is supported
        if (!mxClient.isBrowserSupported()) {
            // Displays an error message if the browser is not supported.
            mxUtils.error('Browser is not supported!', 200, false)
        } else {
            // Disables the built-in context menu
            mxEvent.disableContextMenu(this.container);//取消默认右键菜单
            mxMarker.addMarker('newArrow', this.createMyArrow(2));
            this.createRect();
            this.createMessage();
            this.enableGuides();

            var graph = this.mxGraph;
            var outline = new mxOutline(graph,this.outlineContainer);
            this.undoManager = new mxUndoManager();
            const m = this.undoManager;
            var undoAndRedoListener  = function(sender, evt) {
                // this.undoManager.undoableEditHappened(evt.getProperty('edit'));
                m.undoableEditHappened(evt.getProperty('edit'));
            };

            graph.getModel().addListener(mxEvent.UNDO,undoAndRedoListener);
            graph.getView().addListener(mxEvent.UNDO,undoAndRedoListener);

            // var parent = graph.getDefaultParent();
            // graph.getModel().beginUpdate();
            // try {
            //     graph.insertVertex(parent, null, 'World!', 200, 150, 80, 30);
            // }
            // finally {
            //     graph.getModel().endUpdate();
            // }
            graph.dropEnabled = true;//指定图可以拖拽
            mxDragSource.prototype.getDropTarget = function(graph, x, y)//定义拖拽函数
            {
                var cell = graph.getCellAt(x, y);
                if (!graph.isValidDropTarget(cell))
                {
                    cell = null;
                }
                return cell;
            };
            graph.setPanning(true);//按住鼠标右键移动整个图
            graph.setTooltips(true);//鼠标悬浮显示信息
            graph.setConnectable(true);//设置图可以连接
            //设置预连接
            graph.connectionHandler.createEdgeState = function(me)
            {
                var edge = graph.createEdge(null, null, null, null, null);
                return new mxCellState(this.graph.view, edge, this.graph.getCellStyle(edge));
            };
            graph.getStylesheet().getDefaultEdgeStyle()['edgeStyle'] = 'orthogonalEdgeStyle';

            // mxRubberband(graph);//定义矩形多选
            //
            this.setKeyHandler();
            if (this.toolbarContainer) {
                this.initToolbar();
            }
            this.popupMenu();
        }
    }
    unDo(){
        this.undoManager.undo();
    }
    reDo(){
        this.undoManager.redo();
    }
    zoomIn(){
        this.mxGraph.zoomIn();
    }
    zoomOut(){
        this.mxGraph.zoomOut();
    }
    show(){
        this.editor.execute('show');
    }
    print(){
        this.editor.execute('print');
    }
    removeCell(){
        this.mxGraph.removeCell();
    }
    popupMenu()
    {
        const graph = this.mxGraph;
        // 右键菜单
        graph.popupMenuHandler.factoryMethod = function(menu, cell, evt)
        {
            return createPopupMenu(graph, menu, cell, evt);
        };
        function editStyle(cell, str) {
            var style = cell.getStyle();
            var styleArr = style.split(';');
            var flag=false;
            for(var i = 0;i<styleArr.length;i++)
            {
                for(var j = 0;j<styleArr[i].length && j<str.length;j++)
                {
                    if(styleArr[i][j] !== str[j])
                        break;
                    if(styleArr[i][j]==='=')
                    {
                        flag = true;
                        break;
                    }
                }
                if(flag)
                {
                    styleArr[i]= str;
                    break;
                }
            }
            if(flag===false) return  styleArr.join(';')+str+';';
            else return styleArr.join(';');
        }
        function createPopupMenu(graph, menu, cell, evt)
        {
            if(cell == null) return;
            if(cell.isEdge())
            {
                menu.addItem('条件箭头', readAndWriteImg, function()
                {
                    var model = graph.getModel();
                    model.beginUpdate();
                    try {
                        model.setStyle(cell,editStyle(cell,'endArrow=newArrow'));
                        model.setStyle(cell,editStyle(cell,'dashed=none'));
                        // console.log(cell.getStyle());
                    }
                    finally {
                        model.endUpdate();
                    }
                });
                menu.addItem('单信封', onlyReadImg, function()
                {
                    var model = graph.getModel();
                    model.beginUpdate();
                    try {
                        var message = graph.insertVertex(cell,null,'',0,0,20,14,'shape=message;');
                        message.geometry.offset = new mxPoint(-5, -10);
                        message.geometry.relative = true;
                        message.connectable = false;
                    }
                    finally {
                        model.endUpdate();
                    }
                });
                menu.addItem('多信封', writeImg, function()
                {
                    var model = graph.getModel();
                    model.beginUpdate();
                    try {
                        var message1 = graph.insertVertex(cell,null,'',0,0,20,14,'shape=message');
                        message1.geometry.offset = new mxPoint(-10, -15);
                        message1.geometry.relative = true;
                        message1.connectable = false;

                        var message2 = graph.insertVertex(cell,null,'',0,0,20,14,'shape=message');
                        message2.geometry.offset = new mxPoint(-5, -10);
                        message2.geometry.relative = true;
                        message2.connectable = false;
                    }
                    finally {
                        model.endUpdate();
                    }
                });
                menu.addItem('编辑Artifact', editImg, function()
                {
                    graph.startEditingAtCell(cell,null);
                });
                menu.addItem('删除',deleteImg,function () {
                    if (graph.isEnabled())
                    {
                        graph.removeCells();
                    }
                });
            }
            else {
                if(cell.style==='') {
                    console.log("rect");
                }
                else console.log("circle");
                console.log(cell);
                menu.addItem('删除',deleteImg,function () {
                    if (graph.isEnabled())
                    {
                        graph.removeCells();
                    }
                });
            }
        }
    }

    initToolbar() {
        const graph = this.mxGraph;
        const toolbar = new mxToolbar(this.toolbarContainer);
        const _this = this;

        graph.getTooltipForCell = function(cell)
        {
            return cell.id;
        };
        toolbar.enabled = false;//指定是否处理事件
        addVertex(ellipseImg,70,70,'shape=ellipse');
        addVertex(rectangleImg, 70,100,'shape=myshape');
        // 添加工作条元素
        function addVertex(icon, w, h, style) {
            const vertex = new mxCell('请输入文本', new mxGeometry(0, 0, w, h), style);
            vertex.setVertex(true);
            addToolbarItem(graph, toolbar, vertex, icon);
        }
        // 绑定工作条元素事件
        function addToolbarItem(graph, toolbar, prototype, image) {
            var funct = function(graph, evt, cell) {
                graph.stopEditing(false);
                var pt = graph.getPointForEvent(evt);
                var vertex = graph.getModel().cloneCell(prototype);
                vertex.geometry.x = pt.x;
                vertex.geometry.y = pt.y;

                // 对新增的节点id给定uuid
                var cells = graph.importCells([vertex], 0, 0, cell);
                graph.setSelectionCells(cells);
                // graph.setSelectionCells(graph.importCells([vertex], 0, 0, cell));
            };
            // Creates the image which is used as the drag icon (preview)
            const img = toolbar.addMode(null, image, funct);
            mxUtils.makeDraggable(img, graph, funct);
        }
    }


}

export { Graph }
